﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace SickBox
{
    public static class Util
    {
        /// <summary>
        /// Generates the public/private keypair
        /// </summary>
        /// <returns>the private key as an XML string</returns>
        public static String GenerateKeyPair()
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            String _privateKey = rsa.ToXmlString(true);
            String _publicKey = rsa.ToXmlString(true);
            File.WriteAllText("public.sb", _publicKey);
            if (File.Exists("public.sb"))
            {
                Console.WriteLine("Keys Successfully Generated.");
                Console.WriteLine("Public Key Located at: " + Path.GetFullPath("public.sb"));
            }

            return _privateKey;
        }

        public static Dictionary<String, byte[]> Encrypt(this String path, String _publickey)
        {
            Console.Write("Encrypting '" + Path.GetFileName(path) + "'...");
            Dictionary<String, byte[]> dic = new Dictionary<String, byte[]>();
            RijndaelManaged rManaged = new RijndaelManaged();
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

            rsa.FromXmlString(_publickey);

            rManaged.GenerateKey();
            rManaged.GenerateIV();

            byte[] key = rManaged.Key;
            byte[] iv = rManaged.IV;

            try
            {
                using (rManaged)
                {
                    byte[] inputFiledata;
                    ICryptoTransform encryptor = rManaged.CreateEncryptor(rManaged.Key, rManaged.IV);
                    using (FileStream inputFileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
                    {
                        inputFiledata = new byte[(int)inputFileStream.Length];
                        inputFileStream.Read(inputFiledata, 0, (int)inputFileStream.Length);
                        using (CryptoStream encryptStream = new CryptoStream(inputFileStream, encryptor, CryptoStreamMode.Write))
                        {
                            encryptStream.Write(inputFiledata, 0, (int)inputFileStream.Length);
                            encryptStream.FlushFinalBlock();
                        }
                    }
                    dic.Add(Path.GetFileName(path), inputFiledata);
                    
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Encryption went wrong.");
                Console.WriteLine("---------------------------------------------");
                Console.WriteLine(ex.Message);
                Console.WriteLine("---------------------------------------------");
                return null;
            }

            byte[] encryptedRKey = rsa.Encrypt(key, true);
            byte[] encryptedRIV = rsa.Encrypt(iv, true);

            dic.Add("Key", encryptedRKey);
            dic.Add("IV", encryptedRIV);

            Console.WriteLine("Done.");

            return dic;
        }

        public static IPEndPoint CreateIPEndPoint(string endPoint)
        {
            string[] ep = endPoint.Split(':');
            if (ep.Length < 2)
            {
                Console.WriteLine("The IP Address is malformed. The Port number needs to be 2 characters or more.");
                return null;
            }
            IPAddress ip;
            if (ep.Length > 2)
            {
                if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip))
                {
                    Console.WriteLine("Invalid ip-adress!");
                    return null;
                }
            }
            else
            {
                if (!IPAddress.TryParse(ep[0], out ip))
                {
                    Console.WriteLine("Invalid ip-adress!");
                    return null;
                }
            }
            int port;
            if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
            {
                Console.WriteLine("Invalid port");
                return null;
            }
            return new IPEndPoint(ip, port);
        }
    }
}
